use crate::Exception;
use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, Timelike};
use std::collections::HashMap;

/// Basic data objects (including Number, String, bool, none, and time)
#[derive(Debug)]
pub enum Object {
    Integer32(i32),
    Long64(i64),
    String(String),
    Float32(f32),
    Double64(f64),
    Boolean(bool),
    Date(NaiveDate),
    DateTime(NaiveDateTime),
    None,
}

impl From<&str> for Object {
    fn from(s: &str) -> Self {
        Object::String(s.to_string())
    }
}
impl From<i32> for Object {
    fn from(value: i32) -> Self {
        Object::Integer32(value)
    }
}

impl From<i64> for Object {
    fn from(value: i64) -> Self {
        Object::Long64(value)
    }
}

impl From<f32> for Object {
    fn from(value: f32) -> Self {
        Object::Float32(value)
    }
}

impl From<f64> for Object {
    fn from(value: f64) -> Self {
        Object::Double64(value)
    }
}

impl From<bool> for Object {
    fn from(value: bool) -> Self {
        Object::Boolean(value)
    }
}

impl From<sqlite::Value> for Object {
    fn from(value: sqlite::Value) -> Self {
        match value {
            sqlite::Value::Float(value) => Object::Double64(value),
            sqlite::Value::Integer(value) => Object::Long64(value),
            sqlite::Value::String(value) => Object::String(value),
            _ => Object::None,
        }
    }
}

impl From<&sqlite::Value> for Object {
    fn from(value: &sqlite::Value) -> Self {
        match value {
            sqlite::Value::Float(value) => Object::Double64(*value),
            sqlite::Value::Integer(value) => Object::Long64(*value),
            sqlite::Value::String(value) => Object::String(value.to_string()),
            _ => Object::None,
        }
    }
}

impl TryFrom<mysql_common::Value> for Object {
    type Error = mysql_common::FromValueError;

    fn try_from(value: mysql_common::Value) -> Result<Self, Self::Error> {
        // TODO 此处有问题，通过这种方式返回的值，全部是Bytes类型，没有根据数据库实际情况返回对应的类型，如int，string，float等
        println!("{:?}", value);

        let res = match value {
            mysql_common::Value::Int(v) => Object::Integer32(v as i32),
            mysql_common::Value::UInt(v) => Object::Long64(v as i64),
            mysql_common::Value::Float(v) => Object::Float32(v),
            mysql_common::Value::Double(v) => Object::Double64(v),
            mysql_common::Value::Bytes(u8_arr) => Object::String(String::from_utf8(u8_arr).unwrap()),
            mysql_common::Value::Date(year, month, day, hour, minute, second, ms) => {
                let dt = Local::now();
                let dt = dt.with_year(year as i32).unwrap()
                    .with_month(month as u32).unwrap()
                    .with_day(day as u32).unwrap()
                    .with_hour(hour as u32).unwrap()
                    .with_minute(minute as u32).unwrap()
                    .with_second(second as u32).unwrap()
                    .with_nanosecond(ms).unwrap();
                Object::DateTime(dt.naive_local())
            },
            _ => Object::None,
        };
        Ok(res)
    }
}

impl mysql_common::value::convert::FromValue for Object {
    type Intermediate = Object;
    // type Intermediate: TryFrom<Value, Error = FromValueError> + Into<Self>;

    fn from_value(value: mysql_common::value::Value) -> Self {
        match value {
            mysql_common::value::Value::Bytes(bytes) => {
                Object::String(String::from_utf8_lossy(&bytes).to_string())
            }
            mysql_common::value::Value::Int(value) => Object::Long64(value),
            mysql_common::value::Value::UInt(value) => Object::Long64(value as i64),
            _ => Object::None,
        }
    }

    fn from_value_opt(_v: mysql_common::Value) -> Result<Self, mysql_common::FromValueError> {
        todo!()
    }

    fn get_intermediate(_v: mysql_common::Value) -> Result<Self::Intermediate, mysql_common::FromValueError> {
        todo!()
    }
}

impl Object {
    pub fn is_null(&self) -> bool {
        match self {
            Object::None => true,
            _ => false,
        }
    }

    /// 将Object枚举转换为String类型
    ///
    /// # 参数
    /// * `self` - Object枚举的引用
    ///
    /// # 返回值
    /// 返回Option<String>，如果Object为None则返回None，否则返回对应值的字符串表示
    pub fn get_string(&self) -> Option<String> {
        match self {
            // 匹配不同的Object类型并转换为字符串
            Object::None => None,
            Object::Integer32(value) => Some(value.to_string()),
            Object::Long64(value) => Some(value.to_string()),
            Object::Float32(value) => Some(value.to_string()),
            Object::Double64(value) => Some(value.to_string()),
            Object::String(value) => Some(value.to_string()),
            Object::Boolean(value) => Some(value.to_string()),
            Object::Date(value) => Some(value.format("%Y-%m-%d").to_string()),
            Object::DateTime(value) => Some(value.format("%Y-%m-%d %H:%M:%S").to_string()),
        }
    }

    /// 将对象转换为整数类型
    ///
    /// 该函数尝试将当前对象转换为i32类型的整数。根据不同对象类型，
    /// 采用相应的转换规则：整数和长整数直接转换，浮点数截断小数部分，
    /// 布尔值转换为0或1，其他类型返回None。
    ///
    /// # 返回值
    /// * `Option<i32>` - 转换成功返回Some(整数值)，失败返回None
    pub fn get_integer(&self) -> Option<i32> {
        match self {
            // 数值类型直接转换或截断
            Object::Integer32(value) => Some(*value),
            Object::Long64(value) => Some(*value as i32),
            Object::Float32(value) => Some(*value as i32),
            Object::Double64(value) => Some(*value as i32),
            // 布尔类型转换为数字
            Object::Boolean(value) => {
                if *value {
                    Some(1)
                } else {
                    Some(0)
                }
            }
            // 其他类型无法转换
            _ => None,
        }
    }

    /// 将对象转换为64位整数类型
    ///
    /// 该函数尝试将当前对象转换为i64类型的值。根据不同对象类型，
    /// 会进行相应的类型转换或映射。
    ///
    /// # 返回值
    /// - `Some(i64)` - 转换成功时返回对应的64位整数值
    /// - `None` - 当前对象无法转换为整数类型时返回None
    pub fn get_long(&self) -> Option<i64> {
        match self {
            // 数值类型直接转换为i64
            Object::Integer32(value) => Some(*value as i64),
            Object::Long64(value) => Some(*value),
            Object::Float32(value) => Some(*value as i64),
            Object::Double64(value) => Some(*value as i64),
            // 布尔类型映射：true->1, false->0
            Object::Boolean(value) => {
                if *value {
                    Some(1)
                } else {
                    Some(0)
                }
            }
            // 其他类型无法转换为整数
            _ => None,
        }
    }

    /// Convert the current object to 32-bit float-point number
    ///
    /// # 返回值
    /// * `Option<f32>` - 转换成功时返回Some(f32)，否则返回None
    ///
    /// # 转换规则
    /// * Integer32: 直接转换为f32
    /// * Long64: 转换为f32（可能丢失精度）
    /// * Float32: 直接返回
    /// * Double64: 转换为f32（可能丢失精度）
    /// * Boolean: true转为1.0，false转为0.0
    /// * 其他类型: 返回None
    pub fn get_float32(&self) -> Option<f32> {
        match self {
            // 数值类型转换为f32
            Object::Integer32(value) => Some(*value as f32),
            Object::Long64(value) => Some(*value as f32),
            Object::Float32(value) => Some(*value),
            Object::Double64(value) => Some(*value as f32),
            // 布尔类型转换：true=1.0, false=0.0
            Object::Boolean(value) => {
                if *value {
                    Some(1.0)
                } else {
                    Some(0.0)
                }
            }
            // 其他不支持的类型返回None
            _ => None,
        }
    }

    /// 将对象转换为双精度浮点数
    ///
    /// 该函数尝试将当前对象转换为f64类型的值。支持的类型包括：
    /// - 整数类型（Integer32、Long64）：直接转换为对应的浮点数
    /// - 浮点数类型（Float32、Double64）：Float32转换为f64，Double64直接返回
    /// - 布尔类型：true转换为1.0，false转换为0.0
    /// - 其他类型：返回None
    ///
    /// # 返回值
    /// * `Option<f64>` - 转换成功返回Some(f64值)，否则返回None
    pub fn get_double(&self) -> Option<f64> {
        match self {
            // 数值类型直接转换为f64
            Object::Integer32(value) => Some(*value as f64),
            Object::Long64(value) => Some(*value as f64),
            Object::Float32(value) => Some(*value as f64),
            Object::Double64(value) => Some(*value),
            // 布尔类型转换为对应的数值
            Object::Boolean(value) => {
                if *value {
                    Some(1.0)
                } else {
                    Some(0.0)
                }
            }
            // 其他类型无法转换，返回None
            _ => None,
        }
    }
}

/// Database operation interface definition (conventional CRUD)
pub trait SqlCrud {
    /// 向数据库中插入数据
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL插入语句
    ///
    /// # 返回值
    /// * `Result<bool, Exception>` - 操作结果
    ///   - 成功时返回布尔值，表示插入操作是否成功执行
    ///   - 失败时返回Exception错误信息
    fn insert(&self, sql: &str) -> Result<bool, Exception>;

    /// 执行SQL更新操作
    ///
    /// 该函数用于执行给定的SQL语句，通常用于INSERT、UPDATE或DELETE操作
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL语句字符串引用
    ///
    /// # 返回值
    /// * `Result<bool, Exception>` - 操作结果
    /// - 成功时返回布尔值，表示操作是否成功执行
    /// - 失败时返回Exception错误信息
    fn update(&self, sql: &str) -> Result<bool, Exception>;

    /// 删除数据库中的记录
    ///
    /// 执行指定的DELETE SQL语句来删除数据库中的记录
    ///
    /// # 参数
    /// * `sql` - 要执行的DELETE SQL语句字符串引用
    ///
    /// # 返回值
    /// * `Result<bool, Exception>` - 操作结果
    ///   - 成功时返回`Ok(true)`表示删除成功
    ///   - 失败时返回`Err(Exception)`包含具体的异常信息
    fn delete(&self, sql: &str) -> Result<bool, Exception>;

    /// 从数据库中执行SELECT查询并返回单行结果
    ///
    /// 该函数执行传入的SQL SELECT语句，期望返回单行数据。
    /// 如果查询成功，将结果转换为键值对形式的HashMap返回，
    /// 其中键为列名，值为对应的数据库字段值。
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL SELECT查询语句
    ///
    /// # 返回值
    /// * `Ok(HashMap<String, Object>)` - 查询成功，返回包含列名和对应值的映射
    /// * `Err(Exception)` - 查询失败，返回异常信息
    ///
    /// # 错误处理
    /// 当SQL语句执行失败、连接数据库出错或结果解析异常时，会返回相应的错误信息
    fn select_one(&self, sql: &str) -> Result<HashMap<String, Object>, Exception>;

    /// 执行SQL查询语句并返回结果集
    ///
    /// 该函数用于执行SELECT类型的SQL查询，将查询结果转换为键值对的向量形式返回。
    ///
    /// # 参数
    /// * `sql` - 要执行的SQL查询语句字符串引用
    ///
    /// # 返回值
    /// * `Result<Vec<HashMap<String, Object>>, Exception>` - 执行结果
    ///   - 成功时返回包含查询结果的向量，每个元素是一个HashMap，表示一行数据，键为列名，值为对应的数据值
    ///   - 失败时返回Exception错误信息
    fn select(&self, sql: &str) -> Result<Vec<HashMap<String, Object>>, Exception>;
}